package com.qumitech.visualnovel.service.chat.impl;

import com.alibaba.fastjson.JSONObject;
import com.qumitech.visualnovel.component.exception.BusinessException;
import com.qumitech.visualnovel.component.util.CommonUtil;
import com.qumitech.visualnovel.component.util.HttpInvokeUtil;
import com.qumitech.visualnovel.component.util.DateUtil;
import com.qumitech.visualnovel.model.common.BaseRsp;
import com.qumitech.visualnovel.model.common.ResultEnum;
import com.qumitech.visualnovel.datasource.console.ChatRiskWordMapper;
import com.qumitech.visualnovel.datasource.nocore.ChatMsgDOMapper;
import com.qumitech.visualnovel.datasource.app.UserForbiddenMapper;
import com.qumitech.visualnovel.datasource.app.AccountMapper;
import com.qumitech.visualnovel.datasource.app.VoiceRoomMapper;
import com.qumitech.visualnovel.datasource.app.IMChatgroupInfoDOMapper;
import com.qumitech.visualnovel.model.dao.console.ChatRiskWord;
import com.qumitech.visualnovel.model.dao.console.UserInfo;
import com.qumitech.visualnovel.model.dao.app.Account;
import com.qumitech.visualnovel.model.dao.app.VoiceRoom;
import com.qumitech.visualnovel.model.dao.app.IMChatgroupInfoDO;
import com.qumitech.visualnovel.model.common.UrlConstant;
import com.qumitech.visualnovel.pubdef.dto.chat.*;
import com.qumitech.visualnovel.service.chat.ChatMsgService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.google.common.collect.ImmutableMap;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author ywxie
 * @date 2019/8/19 10:04
 * @description
 */
@Service
public class ChatMsgServiceImpl implements ChatMsgService {

    private static final String ChatMsg_Url = "/chatmsg/console";

    @Autowired
    private DateUtil dateUtil;

    @Autowired
    private ChatMsgDOMapper chatMsgDOMapper;

    @Autowired
    private ChatRiskWordMapper chatRiskWordMapper;

    @Autowired
    private UserForbiddenMapper userForbiddenMapper;

    @Autowired
    private AccountMapper accountMapper;

    @Autowired
    private VoiceRoomMapper voiceRoomMapper;

    @Autowired
    private IMChatgroupInfoDOMapper imChatgroupInfoDOMapper;

    private String escapeExprSpecialWord(String keyword) {
        String[] specialWords = { "\\", "$", "(", ")", "*", "+", ".", "[", "]", "?", "^", "{", "}", "|" };
        for (String key : specialWords) {
            if (keyword.contains(key)) {
                keyword = keyword.replace(key, "\\" + key);
            }
        }
        return keyword;
    }

    @Override
    public BaseRsp getChatMsgList(ChatMsgAdminQueryDTO chatMsgAdminQueryDTO) {
        List<Long> fromUidList = null;
        String fromUid = chatMsgAdminQueryDTO.getFromUid();
        if (fromUid != null) {
            fromUidList = new ArrayList<>();
            fromUidList.add(Long.valueOf(fromUid));
        }

        String fromUidStatus = chatMsgAdminQueryDTO.getFromUidStatus();
        if (fromUidStatus!=null && fromUidStatus.equals("0")) {
            String startTime = fromUid==null ? chatMsgAdminQueryDTO.getStartTime() : null;
            String endTime = fromUid==null ? chatMsgAdminQueryDTO.getEndTime() : null;
            fromUidList = userForbiddenMapper.getForbiddenUidList(fromUidList, startTime, endTime);
            if (fromUidList.size() == 0) {
                JSONObject respData = new JSONObject();
                respData.put("count", fromUidList.size());
                respData.put("chatmsg_list", fromUidList);
                return new BaseRsp(ResultEnum.SUCCESS, respData);
            }
        }

        String category = chatMsgAdminQueryDTO.getCategory();
        String toUid = chatMsgAdminQueryDTO.getToUid();
        if (category.equals("voiceroom") && toUid!=null) {
            VoiceRoom voiceRoom = voiceRoomMapper.getVoiceRoomByUid(toUid);
            toUid = voiceRoom!=null ? voiceRoom.getRoomId() : toUid;
        }

        String msgContent = chatMsgAdminQueryDTO.getMsgContent();
        String limitType = chatMsgAdminQueryDTO.getLimitType();
        String startTime = chatMsgAdminQueryDTO.getStartTime();
        String endTime = chatMsgAdminQueryDTO.getEndTime();
        int offset = Integer.parseInt(chatMsgAdminQueryDTO.getOffset());
        int limit = Integer.parseInt(chatMsgAdminQueryDTO.getLimit());

        Calendar calendar = new GregorianCalendar();
        SimpleDateFormat dtFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date startDate = null;
        Date endDate = null;
        try {
            startDate = dtFormat.parse(startTime);
            endDate = dtFormat.parse(endTime);
        } catch (ParseException e){
            e.printStackTrace();
        }

        List<Date> timeRange = dateUtil.getTimeRange(startTime, endTime);
        Collections.reverse(timeRange);

        int countInfo = 0;
        List<ChatMsgQueryDTO> dataInfo = new ArrayList<>();
        Set<String> senderSet = new HashSet<>();
        Set<Long> receiverSet = new HashSet<>();

        for (Date curDate : timeRange) {
            calendar.setTime(curDate);
            String tableName = String.format("chatmsg_%d_%d", calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH)+1);

            calendar.add(calendar.SECOND, 86399);
            Date curStartDate = curDate.after(startDate) ? curDate : startDate;
            Date curEndDate = calendar.getTime().before(endDate) ? calendar.getTime() : endDate;

            String curStartTime = dtFormat.format(curStartDate);
            String curEndTime = dtFormat.format(curEndDate);

            int curCount = 0;
            if (fromUid!=null && toUid==null) {
                List<Long> toList = chatMsgDOMapper.getStatisticToList(tableName, fromUid,
                    category, msgContent, limitType, curStartTime, curEndTime);
                curCount = toList.size();
                if (curCount > 0)
                    senderSet.add(fromUid);
                for (Long receiver : toList)
                    receiverSet.add(receiver);
            } else if (fromUid==null && toUid!=null) {
                List<String> fromList = chatMsgDOMapper.getStatisticFromList(tableName, toUid,
                    category, msgContent, limitType, curStartTime, curEndTime);
                curCount = fromList.size();
                if (curCount > 0)
                    receiverSet.add(Long.valueOf(toUid));
                for (String sender : fromList)
                    senderSet.add(sender);
            } else if (fromUid!=null && toUid!=null && category.equals("im")) {
                curCount = chatMsgDOMapper.getImInteractiveMsgCount(tableName, fromUid, toUid,
                    category, msgContent, limitType, curStartTime, curEndTime);
                if (curCount > 0) {
                    senderSet.add(fromUid);
                    receiverSet.add(Long.valueOf(toUid));
                }
            } else {
                curCount = chatMsgDOMapper.getChatMsgCount(tableName, fromUidList, toUid,
                    category, msgContent, limitType, curStartTime, curEndTime);
                if (fromUid!=null && toUid!=null && curCount>0) {
                    senderSet.add(fromUid);
                    receiverSet.add(Long.valueOf(toUid));
                }
            }

            if ((countInfo+curCount)>offset && limit>dataInfo.size()) {
                int curOffset = dataInfo.size()==0 ? (offset-countInfo) : 0;
                int curLimit = limit - dataInfo.size();
                if (fromUid!=null && toUid!=null && category.equals("im")) {
                    List<ChatMsgQueryDTO> curInfo = chatMsgDOMapper.getImInteractiveMsgList(tableName, fromUid,
                        toUid, category, msgContent, limitType, curStartTime, curEndTime, curOffset, curLimit);
                    dataInfo.addAll(curInfo);
                } else {
                    List<ChatMsgQueryDTO> curInfo = chatMsgDOMapper.getChatMsgList(tableName, fromUidList,
                        toUid, category, msgContent, limitType, curStartTime, curEndTime, curOffset, curLimit);
                    dataInfo.addAll(curInfo);
                }
            }
            countInfo = countInfo + curCount;
        }

        if (category.equals("voiceroom")) {
            setVoiceRoomInfo(dataInfo);
        }

        Set<String> fromIdSet = new HashSet<>();
        Set<String> toIdSet = new HashSet<>();
        Set<Long> fromUidSet = new HashSet<>();
        for (ChatMsgQueryDTO data : dataInfo) {
            fromIdSet.add(data.getFromId());
            toIdSet.add(String.valueOf(data.getToId()));
            fromUidSet.add(Long.valueOf(data.getFromId()));
        }

        Map<Long, String> nicknameMap = getNicknameMap(fromIdSet);
        Map<Long, Boolean> forbiddenMap = getForbiddenMap(fromUidSet);
        Map<Long, String> toNameMap = getToNameMap(category, toIdSet);
        for (ChatMsgQueryDTO data : dataInfo) {
            data.setFromIdName(nicknameMap);
            data.setToIdName(toNameMap);
            data.setForbidden(forbiddenMap);
        }

        JSONObject jsonObj = new JSONObject();
        jsonObj.put("count", countInfo);
        jsonObj.put("chatmsg_list", dataInfo);
        if (fromUid!=null || toUid!=null) {
            JSONObject statistic = new JSONObject();
            statistic.put("msgTimes", countInfo);
            statistic.put("senderNum", senderSet.size());
            statistic.put("receiverNum", receiverSet.size());
            jsonObj.put("statistic", statistic);
        }
        return new BaseRsp(ResultEnum.SUCCESS, jsonObj);
    }

    private void setVoiceRoomInfo(List<ChatMsgQueryDTO> dataInfo) {
        Set<String> roomIdSet = new HashSet<>();
        for (ChatMsgQueryDTO data : dataInfo) {
            roomIdSet.add(String.valueOf(data.getToId()));
        }

        Map<Long, Long> voiceroomNameMap = new HashMap<>();
        List<String> roomIdList = new ArrayList<>(roomIdSet);
        List<VoiceRoom> voiceRoomInfo = voiceRoomMapper.listWithRoomIds(roomIdList);
        for (VoiceRoom voiceroom : voiceRoomInfo) {
            voiceroomNameMap.put(Long.valueOf(voiceroom.getRoomId()), voiceroom.getUid());
        }

        for (ChatMsgQueryDTO data : dataInfo) {
            Long voiceRoomId = data.getToId();
            if (voiceroomNameMap.containsKey(voiceRoomId)) {
                data.setToId(voiceroomNameMap.get(voiceRoomId));
            }
        }
    }

    private Map<Long, String> getNicknameMap(Set<String> uidSet) {
        List<String> uidList = new ArrayList(uidSet);
        List<Account> accountList = accountMapper.getNicknameList(uidList);

        Map<Long, String> nicknameMap = new HashMap<>();
        for (Account item : accountList) {
            nicknameMap.put(item.getUid(), item.getUserName());
        }
        return nicknameMap;
    }

    private Map<Long, Boolean> getForbiddenMap(Set<Long> uidSet) {
        List<Long> uidList = new ArrayList(uidSet);
        List<Long> forbiddenList = userForbiddenMapper.getForbiddenUidList(uidList, null, null);
        Map<Long, Boolean> forbiddenMap = new HashMap<>();
        for (Long uid : forbiddenList) {
            forbiddenMap.put(uid, true);
        }
        return forbiddenMap;
    }

    private Map<Long, String> getToNameMap(String category, Set<String> toIdSet) {
        if (category.equals("im")) {
            return getNicknameMap(toIdSet);
        } else if (category.equals("voiceroom")) {
            return getNicknameMap(toIdSet);
        } else if (category.equals("groupchat")) {
            List<String> groupIdList = new ArrayList<>(toIdSet);
            Map<Long, String> chatGroupNameMap = new HashMap<>();
            List<IMChatgroupInfoDO> chatGroupInfo = imChatgroupInfoDOMapper.getChatGroupNameListByPlatId(groupIdList);
            for (IMChatgroupInfoDO chatGroup : chatGroupInfo) {
                chatGroupNameMap.put(chatGroup.getPlatId(), chatGroup.getGroupName());
            }
            return chatGroupNameMap;
        }
        return new HashMap<>();
    }

    @Override
    public BaseRsp updateChatMsg(ChatMsgAdminUpdateDTO updateDTO) {
        String url = UrlConstant.SERVER_URL + ChatMsg_Url + "/change_status";
        String req = JSONObject.toJSONString(updateDTO);
        String body = HttpInvokeUtil.httpPutJson(url, req, UrlConstant.DefaultEncode, null);
        return JSONObject.parseObject(body, BaseRsp.class);
    }

    @Override
    public void addRiskWord(RiskWordSaveDTO saveDTO) {
        Subject subject = SecurityUtils.getSubject();
        UserInfo activeUser = (UserInfo) subject.getPrincipal();
        for(String word: saveDTO.getWords())
        {
            ChatRiskWord chatRiskWord = new ChatRiskWord();
            chatRiskWord.setWord(word);
            chatRiskWord.setStatus(saveDTO.getStatus());
            chatRiskWord.setOperator(activeUser.getUsername());
            chatRiskWordMapper.insertSelective(chatRiskWord);
        }
    }

    @Override
    public void updateRiskWord(RiskWordUpdateDTO updateDTO) {
        Subject subject = SecurityUtils.getSubject();
        UserInfo activeUser = (UserInfo) subject.getPrincipal();
        ChatRiskWord chatRiskWord = new ChatRiskWord();
        chatRiskWord.setStatus(updateDTO.getStatus());
        chatRiskWord.setId(updateDTO.getId());
        chatRiskWord.setWord(updateDTO.getWord());
        chatRiskWord.setOperator(activeUser.getUsername());
        chatRiskWordMapper.updateByPrimaryKeySelective(chatRiskWord);
    }

    @Override
    public void rmRiskWord(Long id) {
        chatRiskWordMapper.deleteByPrimaryKey(id);
    }


    @Override
    public List<ChatRiskWord> listRiskWord(RiskWordQueryDTO queryDTO) {
        return chatRiskWordMapper.listRiskWord(queryDTO);
    }

    @Override
    public int countRiskWord(RiskWordQueryDTO queryDTO) {
        return chatRiskWordMapper.countRiskWord(queryDTO);
    }
}
